// Tencent is pleased to support the open source community by making
// 蓝鲸智云 - 监控平台/日志平台 (BlueKing - Monitor/Log) available.
// Copyright (C) 2017-2022 THL A29 Limited, a Tencent company. All rights reserved.
// Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://opensource.org/licenses/MIT
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//

package receiver

import (
	"fmt"
	"net/http"
	"sort"

	"github.com/gorilla/mux"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"google.golang.org/grpc"

	"github.com/TencentBlueKing/bk-collector/define"
)

func init() {
	err := registerHttpRoute("prom", http.MethodGet, "/metrics", func(w http.ResponseWriter, r *http.Request) {
		promhttp.Handler().ServeHTTP(w, r)
	})
	if err != nil {
		panic(err)
	}
}

type RouteInfo struct {
	Source     string
	HttpMethod string
	Path       string
}

func (r RouteInfo) Key() string { return fmt.Sprintf("%s %s", r.HttpMethod, r.Path) }
func (r RouteInfo) ID() string  { return fmt.Sprintf("%s/%s/%s", r.Source, r.HttpMethod, r.Path) }

type routerManager struct {
	routes   map[string]RouteInfo
	encoders map[string]struct{}
	router   *mux.Router
}

var routerMgr = &routerManager{
	routes:   map[string]RouteInfo{},
	encoders: map[string]struct{}{},
	router:   mux.NewRouter(),
}

// HttpRouter 返回全局 mux.Router
func HttpRouter() *mux.Router {
	return routerMgr.router
}

// OtlpEncoders 返回已经注册的 encoders
func OtlpEncoders() []string {
	var s []string
	for k := range routerMgr.encoders {
		s = append(s, k)
	}
	return s
}

// HttpRoutes 返回已经注册的路由表
func HttpRoutes() []RouteInfo {
	var routes []RouteInfo
	for _, v := range routerMgr.routes {
		routes = append(routes, v)
	}

	sort.Slice(routes, func(i, j int) bool {
		return routes[i].ID() < routes[j].ID()
	})
	return routes
}

type RouteWithFunc struct {
	Method       string
	RelativePath string
	HandlerFunc  http.HandlerFunc
}

// registerHttpRoute 端口需要收敛 所以 server 的控制权转移至上层控制器 调用方只需要注册路由
func registerHttpRoute(source, httpMethod, relativePath string, handleFunc http.HandlerFunc) error {
	ri := RouteInfo{
		Source:     source,
		HttpMethod: httpMethod,
		Path:       relativePath,
	}
	if _, ok := routerMgr.routes[ri.Key()]; ok {
		return fmt.Errorf("duplicated http route '%v'", ri)
	}
	routerMgr.routes[ri.Key()] = ri
	routerMgr.router.HandleFunc(relativePath, handleFunc).Methods(httpMethod)
	return nil
}

// RegisterHttpRoute 注册 Http 路由 失败直接 panic
func RegisterHttpRoute(source string, encoders []Encoder, routes []RouteWithFunc) {
	for i := 0; i < len(routes); i++ {
		r := routes[i]
		if err := registerHttpRoute(source, r.Method, r.RelativePath, r.HandlerFunc); err != nil {
			panic(err)
		}
	}

	for j := 0; j < len(encoders); j++ {
		routerMgr.encoders[fmt.Sprintf("%s:%s", source, encoders[j].Type())] = struct{}{}
	}
}

// RegisterGrpcRoute 注册 Grpc 路由
func RegisterGrpcRoute(register func(s *grpc.Server)) {
	register(globalGrpcSrv)
}

func GetUnmarshal(encoder Encoder, rtype define.RecordType, b []byte) (define.RecordData, error) {
	switch rtype {
	case define.RecordTraces:
		data, err := encoder.UnmarshalTraces(b)
		return define.RecordData{Count: data.SpanCount(), Data: data}, err
	case define.RecordMetrics:
		data, err := encoder.UnmarshalMetrics(b)
		return define.RecordData{Count: data.MetricCount(), Data: data}, err
	case define.RecordLogs:
		data, err := encoder.UnmarshalLogs(b)
		return define.RecordData{Count: data.LogRecordCount(), Data: data}, err
	}
	return define.RecordData{}, define.ErrUnknownRecordType
}
